package com.zjw.zy.viewmodel

import android.media.MediaPlayer
import android.media.MediaRecorder
import android.os.Build
import androidx.lifecycle.LiveData
import androidx.lifecycle.MutableLiveData
import com.zjw.zy.base.BaseViewModel
import com.zjw.zy.bean.RecorderItem
import com.zjw.zy.datasource.database.AppDataBase
import com.zjw.zy.ext.launchInMain
import com.zjw.zy.ext.onIo
import com.zjw.zy.ext.requireService
import com.zjw.zy.smi.JustWithIt
import com.zjw.zy.utils.AppUtils
import com.zjw.zy.utils.PathUtils
import io.reactivex.Observable
import io.reactivex.android.schedulers.AndroidSchedulers
import io.reactivex.disposables.Disposable
import remotecall.RemoteCallManager
import java.io.File
import java.util.*
import java.util.concurrent.TimeUnit
import kotlin.math.min

/**
 * @author     ：zhong.jw
 * @date       ：Created in 2022/10/17 15:54
 * @description：录音
 */
class RecorderViewModel : BaseViewModel() {

    private var mCurrentRecorderItem: RecorderItem? = null
    private var disposable: Disposable? = null
    private var mediaRecorder: MediaRecorder? = null
    private var mediaPlayer: MediaPlayer? = null

    private val timeRecorder: MutableLiveData<Int> = MutableLiveData()

    //current:total
    private val timePlayer: MutableLiveData<Pair<Int, Int>> = MutableLiveData()
    private val state: MutableLiveData<Int> = MutableLiveData()
    private val recorderData: MutableLiveData<List<RecorderItem>> = MutableLiveData()

    fun getTimeRecorder(): LiveData<Int> = timeRecorder
    fun getTimePlayer(): LiveData<Pair<Int, Int>> = timePlayer
    fun getState(): LiveData<Int> = state

    fun getRecorderData(): LiveData<List<RecorderItem>> = recorderData


    //音频输出路径
    private var recorderPath: String = ""

    fun startRecorder() {
        mediaRecorder = if (Build.VERSION.SDK_INT >= 31) {
            MediaRecorder(AppUtils.getMainActivity())
        } else {
            MediaRecorder()
        }.apply {
            //设置录音来源
            this.setAudioSource(MediaRecorder.AudioSource.MIC)
            //设置输出格式
            this.setOutputFormat(MediaRecorder.OutputFormat.THREE_GPP)
            //设置编码格式
            this.setAudioEncoder(MediaRecorder.AudioEncoder.AMR_NB)
            //设置输出路径
            recorderPath = PathUtils.genericRecorderFilePath()
            this.setOutputFile(recorderPath)
        }

        mediaRecorder?.apply {
            this.prepare()
            this.start()
        }
        startRecorderTime()
    }

    private fun startRecorderTime() {
        disposable = Observable.interval(0, 1, TimeUnit.MILLISECONDS).observeOn(
            AndroidSchedulers.mainThread()
        ).subscribe {
            timeRecorder.value = it.toInt()
        }
    }

    fun stopRecorder() {
        mediaRecorder?.apply {
            this.stop()
            this.release()
        }
        mediaRecorder = null
        stopRecorderTime()
        //获取时长
        val duration = MediaPlayer().let {
            it.setDataSource(recorderPath)
            it.prepare()
            val d = it.duration
            it.release()
            return@let d
        }
        //保存录音文件
        val title = recorderPath.lastIndexOf("/").let { recorderPath.substring(it + 1) }
        val recorderItem =
            RecorderItem(
                0,
                title,
                duration,
                Date().time,
                recorderPath
            )
        onIo {
            AppDataBase.getInstance().recorderDao().insertItem(recorderItem)
        }
    }

    fun startPlay(item: RecorderItem) {
        if (item == mCurrentRecorderItem && mediaPlayer != null) {
            resumePlay()
            return
        }
        if (mediaPlayer == null) {
            mediaPlayer = MediaPlayer().apply {
                this.setDataSource(item.path)
                this.prepare()
                this.start()
                disposable = Observable.interval(0, 100, TimeUnit.MILLISECONDS)
                    .observeOn(AndroidSchedulers.mainThread())
                    .subscribe {
                        val total = this.duration
                        val current = this.currentPosition
                        timePlayer.value = Pair(min(current, total), total)
                        //end
                        if (current == total) {
                            destroyCurrentPlay()
                        }
                    }
            }
            mCurrentRecorderItem = item
        } else {
            //打断
            destroyCurrentPlay()
            startPlay(item)
        }
    }

    private fun destroyCurrentPlay() {
        disposable?.dispose()
        disposable = null
        mediaPlayer?.stop()
        mediaPlayer?.release()
        mediaPlayer = null
    }

    fun pausePlay() {
        if (mediaPlayer?.isPlaying == false) {
            return
        }
        mediaPlayer?.pause()
        disposable?.dispose()
        disposable = null
    }

    fun resumePlay() {
        if (mediaPlayer?.isPlaying == true) {
            return
        }
        mediaPlayer?.apply {
            this.start()
            disposable = Observable.interval(0, 100, TimeUnit.MILLISECONDS)
                .observeOn(AndroidSchedulers.mainThread())
                .subscribe {
                    val total = this.duration
                    val current = this.currentPosition
                    timePlayer.value = Pair(min(current, total), total)
                    //end
                    if (current == total) {
                        destroyCurrentPlay()
                    }
                }
        }
    }

    fun stopPlay() {
        mediaPlayer?.let {
            it.stop()
            it.release()
        }
        destroyCurrentPlay()
        mediaPlayer = null
    }

    private fun stopRecorderTime() {
        disposable?.dispose()
        disposable = null
        timeRecorder.postValue(0)
    }

    fun delete(item: RecorderItem) {
        onIo {
            AppDataBase.getInstance().recorderDao().deleteItem(item)
            File(item.path).deleteRecursively()
            refreshRecorderData()
        }
    }


    fun deleteAll() {
        onIo {
            val all = AppDataBase.getInstance().recorderDao().queryAll()
            for (item in all) {
                delete(item)
            }
            refreshRecorderData()
        }
    }

    fun refreshRecorderData() {
        onIo {
            val all = AppDataBase.getInstance().recorderDao().queryAll()
            recorderData.postValue(all)
        }
    }

    fun updateItem(recorderItem: RecorderItem) {
        onIo {
            AppDataBase.getInstance().recorderDao().updateItem(recorderItem)

            refreshRecorderData()
        }
    }

    /**
     * @param path 语音路径
     * @param call 回调结果
     * */
    fun requestVoiceToText(path: String, call: JustWithIt<String>) {
        requireService()?.requestVoiceToText(
            path,
            RemoteCallManager.defaultImpl().remoteCall<String> {
                launchInMain {
                    call.onWith(it)
                }
            })
    }
}